﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Drawing;

using DotSpatial.Symbology;
using DotSpatial.Topology;
using DotSpatial.Data;

namespace HAGISV2
{
    /// <summary>
    /// 向量图层。刘加
    /// 此图层由内部生成，外部显示属于只读不可编辑
    /// </summary>
    [Serializable]
    public class FlowVectorLayer : SingleBaseLayer
    {

        public FlowVectorLayer(string id, HyGrid grid, FlowVectorValue[, ,] vectorValues)
            : base(id)
        {
            this._isSelectable = false; //此图层是不可选的

            this._grid = grid;
            this._vectorValues = vectorValues;

            this._isUseVaryLength = false;
            //this._isUseDefaultRatio = false;
            this._vectorLength = 100;
            this._scaleRatio = 0.01;

            this._featureType = FeatureType.Line;

            this.BuildDataset();

            //箭头样式，暂时先写在这里
            this._symbolizer = new LineSymbolizer();
            CartographicStroke stroke = new CartographicStroke();
            stroke.StartCap = System.Drawing.Drawing2D.LineCap.Flat;
            stroke.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
            stroke.Width = 3.0;
            stroke.Color = Color.Black;
            this._symbolizer.Strokes.Clear();
            this._symbolizer.ScaleMode = ScaleMode.Simple;
            this._symbolizer.Strokes.Add(stroke);

        }

        # region 外部设置的属性


        //外观
        [NonSerialized]
        private ILineSymbolizer _symbolizer = new LineSymbolizer();

        public ILineSymbolizer Symbolizer
        {
            get { return _symbolizer; }            
        }


        private Color _lineColor = Color.Black;

        public Color LineColor
        {
            get { return _lineColor; }
            set 
            {
                _lineColor = value;
                if (this._symbolizer == null)
                {
                    //箭头样式，暂时先写在这里
                    this._symbolizer = new LineSymbolizer();
                    CartographicStroke stroke = new CartographicStroke();
                    stroke.StartCap = System.Drawing.Drawing2D.LineCap.Flat;
                    stroke.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
                    stroke.Width = this._lineWidth;
                    stroke.Color = value;
                    this._symbolizer.Strokes.Clear();
                    this._symbolizer.Strokes.Add(stroke);
                    this._symbolizer.ScaleMode = ScaleMode.Simple;
                    return;
                }

                (this._symbolizer.Strokes[0] as CartographicStroke).Color = value;
            }
        }


        private double _lineWidth = 2.0;

        public double LineWidth
        {
            get { return _lineWidth; }
            set 
            {
                _lineWidth = value;

                if (this._symbolizer == null)
                {
                    //箭头样式，暂时先写在这里
                    this._symbolizer = new LineSymbolizer();
                    CartographicStroke stroke = new CartographicStroke();
                    stroke.StartCap = System.Drawing.Drawing2D.LineCap.Flat;
                    stroke.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
                    stroke.Width = value;
                    stroke.Color = this._lineColor;
                    this._symbolizer.Strokes.Clear();
                    this._symbolizer.Strokes.Add(stroke);
                    return;
                }

                (this._symbolizer.Strokes[0] as CartographicStroke).Width = value;
            }
        }

        
        private double _vectorLength = 200;

        /// <summary>
        /// 要绘制的向量线的长度
        /// </summary>
        public double VectorLength
        {
            get { return _vectorLength; }
            set 
            {
                if (this._vectorLength == value) return;

                _vectorLength = value;

                if (_vectorLength < 0)
                {
                    _vectorLength = 0;
                }

                this.UpdateVectorFeatures();
            }
        }


        private bool _isUseVaryLength = false;  //是否使用模长来绘制线

        /// <summary>
        /// 是否使用模长来绘制线
        /// </summary>
        public bool IsUseVaryLength
        {
            get { return _isUseVaryLength; }
            set 
            { 
                _isUseVaryLength = value;
                this.UpdateVectorFeatures();
            }
        }



        //private bool _isUseDefaultRatio = false;  //是否使用默认模长变化比例

        ///// <summary>
        ///// 是否使用默认模长变化比例
        ///// </summary>
        //public bool IsUseDefaultRatio
        //{
        //    get { return _isUseDefaultRatio; }
        //    set 
        //    { 
        //        _isUseDefaultRatio = value;
        //        this.UpdateVectorFeatures();
        //    }
        //}


        private double _scaleRatio = 0.05;  //模长变化比例

        /// <summary>
        /// 模长变化比例
        /// </summary>
        public double ScaleRatio
        {
            get { return _scaleRatio; }
            set 
            {
                _scaleRatio = value;
                this.UpdateVectorFeatures();
            }
        }




        # endregion
        

        # region 需外部输入的数据

        //这里的数据需要 网格坐标、每个网格对应的两个向量值
        //因为这里是二维显示，所以不是三个方向的向量值
        //视图切换变化时，数据的变化是要在这个类里完成还是在外部完成传到这里？？？？？？？


        HyGrid _grid;

        /// <summary>
        /// 网格坐标体系
        /// </summary>
        public HyGrid Grid
        {
            get { return _grid; }
            set 
            {
                _grid = value;                
                //this.Redraw();  //网格更改是不需要重绘的
            }
        }



                       
        int _layerNormalIndex = 1;
        int _layerFrontIndex = 1;
        int _layerRightIndex = 1;

        /// <summary>
        /// 图层索引。要查看的第几层的数据。
        /// 改变时触发 重绘事件
        /// </summary>
        public int LayerIndex
        {
            get 
            {                
                switch (_viewMode)
                {
                    case FMAPVIEW.NORMAL:
                        return _layerNormalIndex > 1 ? _layerNormalIndex : 1;
                    case FMAPVIEW.FRONT:
                        return _layerFrontIndex > 1 ? _layerFrontIndex : 1;
                    case FMAPVIEW.RIGHT:
                        return _layerRightIndex > 1 ? _layerRightIndex : 1;
                    default:
                        return 1;
                }
            }
            set 
            {
                //_layerIndex = value;

                switch (_viewMode)
                {
                    case FMAPVIEW.NORMAL:
                        if (value == _layerNormalIndex || value > this._grid.LayersCount) return;
                        _layerNormalIndex = value;

                        break;
                    case FMAPVIEW.FRONT:
                        if (value == _layerFrontIndex || value > this._grid.RowsCount) return;
                        _layerFrontIndex = value;
                        break;
                    case FMAPVIEW.RIGHT:
                        if (value == _layerRightIndex || value > this._grid.ColsCount) return;
                        _layerRightIndex = value;
                        break;
                    default:
                        return;
                }
                if (this._isLoaded)
                {
                    this.Redraw();
                }
            }
        }


        FlowVectorValue[, ,] _vectorValues;

        /// <summary>
        /// 向量值.改变时触发redraw
        /// </summary>
        public FlowVectorValue[, ,] VectorValues
        {
            get { return _vectorValues; }
            set 
            {
                _vectorValues = value;
                this.Redraw();
            }
        }


        List<int[,]> _iBound;

        private List<int[,]> IBound
        {
            get { return _iBound; }
            set { _iBound = value; }
        }



        # endregion
             


        # region 内部计算出来要存储的数据

        Coordinate[,] _currentCoors;

        /// <summary>
        /// 当前层的坐标
        /// </summary>
        private Coordinate[,] CurrentCoors
        {
            get { return _currentCoors; }
            set { _currentCoors = value; }
        }

        FlowVectorValue[,] _currentVectors;
        
        /// <summary>
        /// 当前层的向量
        /// </summary>
        public FlowVectorValue[,] CurrentVectors
        {
            get { return _currentVectors; }
            set { _currentVectors = value; }
        }


        int[,] _currentIBound;

        public int[,] CurrentIBound
        {
            get { return _currentIBound; }
            set { _currentIBound = value; }
        }



        # endregion



        # region Method  内部辅助方法

        /// <summary>
        ///构建一个二维上平面的向量视图。即在对应的坐标上添加对应的向量图形
        /// </summary>       
        private void UpdateVectorFeatures()
        {
            if (this._currentCoors == null || this._currentVectors == null || this.CurrentIBound==null)
            {
                //说明获取坐标和向量的方法出错或者传入的数据出错
                //Do Nothing
                return;
            }

            //--------------------------------------------------------------------------------------------------//

            (this._dataSet as IFeatureSet).Features.Clear();

            //生成图形，添加图形

            for (int i = 0; i < this._currentCoors.GetLength(0); i++)
            {
                for (int j = 0; j < this._currentCoors.GetLength(1); j++)
                {
                    double vectorLength = Math.Sqrt(this._currentVectors[i, j].vx * this._currentVectors[i, j].vx + this._currentVectors[i, j].vy * this._currentVectors[i, j].vy);

                    if (this._isUseVaryLength == false)
                    {
                        //使用定长
                        if (vectorLength != 0 && this._currentIBound[i,j]==1)
                        {
                            Coordinate[] lineCoor = new Coordinate[2];
                            lineCoor[0] = new Coordinate(this._currentCoors[i, j].X, this._currentCoors[i, j].Y);

                            double x = this._currentCoors[i, j].X + this._currentVectors[i, j].vx * this._vectorLength / vectorLength;
                            double y = this._currentCoors[i, j].Y + this._currentVectors[i, j].vy * this._vectorLength / vectorLength;

                            lineCoor[1] = new Coordinate(x, y);

                            Feature lineFeature = new Feature(FeatureType.Line, lineCoor);

                            (this._dataSet as FeatureSet).Features.Add(lineFeature);

                        }
                        else
                        {

                        }
                    }
                    else
                    {
                        //使用不定长（模长）
                        if (vectorLength != 0 && this._currentIBound[i, j] == 1)
                        {
                            Coordinate[] lineCoor = new Coordinate[2];
                            lineCoor[0] = new Coordinate(this._currentCoors[i, j].X, this._currentCoors[i, j].Y);

                            double x = this._currentCoors[i, j].X + this._currentVectors[i, j].vx * this._scaleRatio;
                            double y = this._currentCoors[i, j].Y + this._currentVectors[i, j].vy * this._scaleRatio;

                            lineCoor[1] = new Coordinate(x, y);

                            Feature lineFeature = new Feature(FeatureType.Line, lineCoor);

                            (this._dataSet as FeatureSet).Features.Add(lineFeature);
                        }
                        else
                        {
                        }
                    }


                }
            }

            (this.dataSet as IFeatureSet).InvalidateVertices();
            this.DefaultManager.CurrentMap.Invalidate();

        }

        /// <summary>
        /// 获取当前视图下当前层的数据，包括坐标和向量信息
        /// </summary>
        /// <param name="coors">存储坐标信息</param>
        /// <param name="vectors">存储向量信息</param>
        private void GetCurrentData()
        {
            //进行一些必要的数据检查
            if (this._grid == null || this._grid.Grid3DCoordinates == null || this._vectorValues == null)
            {
                //数据传错
                return;
            }
            if (this._grid.Grid3DCoordinates.GetLength(0) != this._vectorValues.GetLength(2) ||
                this._grid.Grid3DCoordinates.GetLength(1) != this._vectorValues.GetLength(0) ||
                this._grid.Grid3DCoordinates.GetLength(2) != this._vectorValues.GetLength(1))
            {
                //数据不对应
                return;
            }


            switch (this._viewMode)
            {
                case FMAPVIEW.NORMAL:
                    this.GetNormalData();
                    break;
                case FMAPVIEW.FRONT:
                    this.GetFrontData();
                    break;
                case FMAPVIEW.RIGHT:
                    this.GetRightData();
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 获取正常视图下当前层的数据，包括坐标和向量信息
        /// </summary>
        /// <param name="coors"></param>
        /// <param name="vectors"></param>
        private void GetNormalData()
        {

            if (this._layerNormalIndex > this._grid.LayersCount)
            {
                //如果要查看的层数超出了网格的层数，出错
                return;
            }

            this._currentCoors = new Coordinate[this._grid.Grid3DCoordinates.GetLength(1) , this._grid.Grid3DCoordinates.GetLength(2) ];
            this._currentVectors = new FlowVectorValue[this._grid.Grid3DCoordinates.GetLength(1) , this._grid.Grid3DCoordinates.GetLength(2) ];

            this._currentIBound = new int[this._grid.Grid3DCoordinates.GetLength(1), this._grid.Grid3DCoordinates.GetLength(2)];

            for (int i = 0; i < this._grid.Grid3DCoordinates.GetLength(1) ; i++)
            {
                for (int j = 0; j < this._grid.Grid3DCoordinates.GetLength(2) ; j++)
                {
                    //this._currentCoors[i, j] = new Coordinate(this._grid.Grid3DCoordinates[this._layerNormalIndex - 1, i, j].X / 4 + this._grid.Grid3DCoordinates[this._layerNormalIndex - 1, i, j + 1].X / 4
                    //    + this._grid.Grid3DCoordinates[this._layerNormalIndex - 1, i + 1, j].X / 4 + this._grid.Grid3DCoordinates[this._layerNormalIndex - 1, i + 1, j + 1].X / 4,
                    //    this._grid.Grid3DCoordinates[this._layerNormalIndex - 1, i, j].Y / 4 + this._grid.Grid3DCoordinates[this._layerNormalIndex - 1, i + 1, j].Y / 4 +
                    //     this._grid.Grid3DCoordinates[this._layerNormalIndex - 1, i, j + 1].Y / 4 + this._grid.Grid3DCoordinates[this._layerNormalIndex - 1, i + 1, j + 1].Y / 4);

                    this._currentCoors[i, j] = new Coordinate(this._grid.Grid3DCoordinates[this._layerNormalIndex - 1, i, j].X, this._grid.Grid3DCoordinates[this._layerNormalIndex - 1, i, j].Y);

                    this._currentVectors[i, j] = new FlowVectorValue(this._vectorValues[i, j, this._layerNormalIndex - 1].vx, this._vectorValues[i, j, this._layerNormalIndex - 1].vy, double.NaN);

                    this._currentIBound[i, j] = this._iBound[this._layerNormalIndex - 1][i, j];
                }
            }

        }

        /// <summary>
        /// 获取前视图下当前层的数据，包括坐标和向量信息
        /// </summary>
        /// <param name="coors"></param>
        /// <param name="vectors"></param>
        private void GetFrontData()
        {
            if (this._layerFrontIndex > this._grid.ColsCount)
            {
                //如果要查看的层数超出了网格的层数，出错
                return;
            }

            this._currentCoors = new Coordinate[this._grid.Grid3DCoordinates.GetLength(0) , this._grid.Grid3DCoordinates.GetLength(2)];
            this._currentVectors = new FlowVectorValue[this._grid.Grid3DCoordinates.GetLength(0) , this._grid.Grid3DCoordinates.GetLength(2) ];
            this._currentIBound = new int[this._grid.Grid3DCoordinates.GetLength(0), this._grid.Grid3DCoordinates.GetLength(2)];

            for (int i = 0; i < this._grid.Grid3DCoordinates.GetLength(0) ; i++)
            {
                for (int j = 0; j < this._grid.Grid3DCoordinates.GetLength(2) ; j++)
                {
                    //this._currentCoors[i, j] = new Coordinate
                    //    (this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 1, this._layerFrontIndex, j].X / 4 + this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 1, this._layerFrontIndex, j + 1].X / 4+
                    //this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 2, this._layerFrontIndex, j].X / 4 + this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 2, this._layerFrontIndex, j + 1].X / 4,
                    //    this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 1, this._layerFrontIndex, j].Z / 4 + this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 2, this._layerFrontIndex, j].Z / 4+
                    //this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 1, this._layerFrontIndex, j+1].Z / 4 + this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 2, this._layerFrontIndex, j+1].Z / 4);

                    this._currentCoors[i, j] = new Coordinate(this._grid.Grid3DCoordinates[ i , this._layerFrontIndex - 1, j].X,
                        this._grid.Grid3DCoordinates[i, this._layerFrontIndex - 1, j].Z);

                    this._currentVectors[i, j] = new FlowVectorValue(this._vectorValues[this._layerFrontIndex - 1, j, i].vx, this._vectorValues[this._layerFrontIndex - 1, j, i].vy, double.NaN);
                    this._currentIBound[i, j] = this._iBound[i][this._layerFrontIndex - 1, j];
                }
            }
        }

        /// <summary>
        /// 获取右视图下当前层的数据，包括坐标和向量信息
        /// </summary>
        /// <param name="coors"></param>
        /// <param name="vectors"></param>
        private void GetRightData()
        {
            if (this._layerRightIndex > this._grid.RowsCount)
            {
                //如果要查看的层数超出了网格的层数，出错
                return;
            }

            this._currentCoors = new Coordinate[this._grid.Grid3DCoordinates.GetLength(0), this._grid.Grid3DCoordinates.GetLength(1)];
            this._currentVectors = new FlowVectorValue[this._grid.Grid3DCoordinates.GetLength(0), this._grid.Grid3DCoordinates.GetLength(1)];

            this._currentIBound = new int[this._grid.Grid3DCoordinates.GetLength(0), this._grid.Grid3DCoordinates.GetLength(1)];

            for (int i = 0; i < this._grid.Grid3DCoordinates.GetLength(0) ; i++)
            {
                for (int j = 0; j < this._grid.Grid3DCoordinates.GetLength(1) ; j++)
                {
                    //this._currentCoors[i, j] = new Coordinate(
                    //    this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 1, j, this._layerRightIndex].Y / 4 + this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 1, j + 1, this._layerRightIndex].Y / 4+
                    //this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 2, j, this._layerRightIndex].Y / 4 + this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 2, j + 1, this._layerRightIndex].Y / 4,
                    //    this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 1, j, this._layerRightIndex].Z / 4 + this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 1 - 1, j, this._layerRightIndex].Z / 4+
                    //this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 1, j+1, this._layerRightIndex].Z / 4 + this._grid.Grid3DCoordinates[this._grid.Grid3DCoordinates.GetLength(0) - i - 1 - 1, j+1, this._layerRightIndex].Z / 4);

                    this._currentCoors[i, j] = new Coordinate(this._grid.Grid3DCoordinates[ i, j, this._layerRightIndex - 1].Y,
                        this._grid.Grid3DCoordinates[ i, j, this._layerRightIndex - 1].Z);

                    this._currentVectors[i, j] = new FlowVectorValue(this._vectorValues[j, this._layerRightIndex - 1, i].vx, this._vectorValues[j, this._layerRightIndex - 1, i].vy, double.NaN);

                    this._currentIBound[i, j] = this._iBound[i][j,this._layerRightIndex - 1];
                }
            }
        }


        # endregion


        # region 外部调用。设置数据方法，因为直接赋值可能会引起重绘操做，所里这里加不引起重绘的方法

        public void SetGrid(HyGrid grid)
        {
            this._grid = grid;
        }

        public void SetVectorValues(FlowVectorValue[, ,] values)
        {
            this._vectorValues = values;
        }

        public void SetIBount(List<int[,]> ibound)
        {
            this._iBound = ibound;
        }

        public void SetPara(bool isUseVary, double vectorLength, double scale,Color lineColor)
        {
            this._isUseVaryLength = isUseVary;
            this._vectorLength = vectorLength;
            this._scaleRatio = scale;
            this.LineColor = lineColor;

            this.UpdateVectorFeatures();
        }

        # endregion


        # region 继承的方法。功能函数

        public override void BuildDataset()
        {
            base.BuildDataset();
        }


        public override void Render()
        {
            base.Render();

            if (this._iLayer != null)
            {
                if (this._symbolizer == null)
                {
                    //箭头样式，暂时先写在这里
                    this._symbolizer = new LineSymbolizer();
                    CartographicStroke stroke = new CartographicStroke();
                    stroke.StartCap = System.Drawing.Drawing2D.LineCap.Flat;
                    stroke.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
                    stroke.Width = this._lineWidth;
                    stroke.Color = _lineColor;
                    this._symbolizer.Strokes.Clear();
                    this._symbolizer.ScaleMode = ScaleMode.Simple;
                    this._symbolizer.Strokes.Add(stroke);
                }
                (this._iLayer as IFeatureLayer).Symbolizer = this._symbolizer;
            }
        }


        public override void StopRender()
        {
            base.StopRender();
        }

        public override bool OpenLayer()
        {

            this.BuildDataset();

            this.Render();

            this.Update();

            return true;

        }


        public override bool SaveLayer()
        {
            return base.SaveLayer();
        }


        protected override void OnViewModeChanged()
        {
            this.Redraw();
        }


        protected override void OnSetVisible()
        {
            base.OnSetVisible();
        }
        



        /// <summary>
        /// 重绘。
        /// 1 向量数据本身发生变化时需进行重绘
        /// 2 视图、图层发生变化时也要进行重绘
        /// </summary>
        public override void Redraw()
        {            
            (this._dataSet as IFeatureSet).Features.Clear(); //清空原有图形

            if (this._grid == null || this._vectorValues == null)
            {
                this.ILayer.Invalidate();
                return;
            }
            this.GetCurrentData();   //获取对应视图对应层的坐标和向量数据

            this.UpdateVectorFeatures();  //添加向量数据

            (this._dataSet as IFeatureSet).InvalidateVertices();
            (this._dataSet as IFeatureSet).InitializeVertices();

            (this._iLayer as IFeatureLayer).Invalidate();

            this._defaultManager.CurrentMap.Invalidate();

        }


        # endregion




    }
}
